package jmine.tec.services.integration;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

import jmine.tec.di.annotation.Injected;
import jmine.tec.services.ServicesController;
import jmine.tec.services.annotations.Execution;
import jmine.tec.services.annotations.Input;
import jmine.tec.services.annotations.ServiceImplementor;
import jmine.tec.services.annotations.WithRegex;
import jmine.tec.services.api.ActionsEnum;
import jmine.tec.services.api.RawInput;
import jmine.tec.services.io.ServiceBean;
import jmine.tec.services.io.ServicesPageBean;
import jmine.tec.services.runner.BaseServiceBuilder;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import bancosys.tec.datadigester.DataDigesterController;
import bancosys.tec.services.ServicesIntegrationTestCase;
import bancosys.tec.services.input.driver.bean.ServicePageHeader;
import bancosys.tec.services.input.driver.processor.ThreadSafeServiceProcessor;

/**
 * Service used to execute external spreadsheets as services with parameters.
 * 
 * @author bruno.ortiz
 */
@Transactional(propagation = Propagation.REQUIRES_NEW)
@ServiceImplementor(action = ActionsEnum.EXECUTAR)
public class CenarioService {

	private static final Log LOG = LogFactory.getLog(CenarioService.class);

	private static final String RELATIVE_PATH = "Caminho relativo";

	private static final String PARAMETERS = "Parametro\\s+(\\S+)\\s*";

	private static final String BASE_PATH = "Caminho base";

	private Map<String, String> parameters;

	private ServicesController servicesController;

	private DataDigesterController dataDigesterController;

	@Execution
	public void execute(@Injected RawInput input) throws Exception {
		String basePath = input.getRaw(BASE_PATH);
		String relativePath = input.getRaw(RELATIVE_PATH);

		if (StringUtils.isBlank(basePath)) {
			basePath = input.getRaw(ServicesIntegrationTestCase.INTEGRATION_TEST_LOCATION_URL);
		}

		LOG.info(String.format("Executando cenário.  Caminho base: %s. Caminho relativo: %s. Código do arquivo: %s.", basePath, relativePath,
				"INTEGRACAO-PLANILHA"));
		ServicePageHeader header = this.parseXls(basePath, relativePath);
		this.addIntegrationTestGlobalParameters(header);
		this.processHeader(header);
	}

	private void processHeader(ServicePageHeader header) {
		final ThreadSafeServiceProcessor processor = new ThreadSafeServiceProcessor(this.servicesController);
		processor.process(header);
	}

	private ServicePageHeader parseXls(String base, String relative) throws MalformedURLException, Exception {
		URL url = new URL(base + StringUtils.join(relative.split("/"), File.separator));
		return (ServicePageHeader) this.dataDigesterController.digest("INTEGRACAO-PLANILHA", url.getFile(), url.openStream());
	}

	private void addIntegrationTestGlobalParameters(ServicePageHeader header) {
		ServicesPageBean page = new ServicesPageBean();
		for (Map.Entry<String, String> entry : this.parameters.entrySet()) {
			page.addService(this.createGlobalParameter(entry.getKey(), entry.getValue()));
		}
		header.getWorkSheets().add(0, page);
	}

	private ServiceBean createGlobalParameter(String parameter, String value) {
		BaseServiceBuilder builder = new BaseServiceBuilder(GlobalParameterService.class);
		builder.with(GlobalParameterService.REFERENCE, parameter);
		builder.with(GlobalParameterService.VALUE, value);
		return builder.build();
	}

	@Injected
	public void setServicesController(ServicesController serviceController) {
		this.servicesController = serviceController;
	}

	@Injected
	public void setDataDigesterController(DataDigesterController dataDigesterController) {
		this.dataDigesterController = dataDigesterController;
	}

	@WithRegex(regex = PARAMETERS, groupIndex = 1)
	public void setParameters(Map<String, String> parameters) {
		this.parameters = parameters;
	}

	@Input(fieldName = RELATIVE_PATH)
	public void setPath(String path) {
	}

	@Input(fieldName = BASE_PATH, defaultValue = ServicesIntegrationTestCase.INTEGRATION_TEST_LOCATION_URL)
	public void setBasePath(String basePath) throws MalformedURLException {
	}

}
